home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Mac Game Programming Gurus / TricksOfTheMacGameProgrammingGurus.iso / More Source / Libraries / VideoToolbox 95.04.18 / VideoToolboxSources / SndPlay1.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-01-16  |  5.2 KB  |  161 lines  |  [TEXT/MMCC]

  1. /* 
  2. SndPlay1.c
  3.  
  4. SndPlay1(snd) plays a sound, asynchronously, i.e. it returns immediately, while the
  5. sound is still playing. The argument is a handle to a snd resource. If a sound is 
  6. still playing from a previous call to SndPlay1, it is allowed to finish before
  7. closing and reopening the channel and beginning the new sound.
  8. SndPlay1(NULL) waits for the sound to end and then closes the channel.
  9. SndStop1() closes the channel immediately.
  10. SndDone1() returns true once the last sound initiated by SndPlay1() has 
  11. finished.
  12.  
  13. GENERAL NOTE:
  14. The Apple Sound Manager has the annoying characteristic of insisting on loading
  15. any synth that's mentioned in a snd resource, even if that synth is already loaded,
  16. which causes an error. This makes it necessary to dispose of and recreate the 
  17. snd channel before each new sound, which these routines do. Apple advises against 
  18. this approach because it leaves the channel open a lot of the time, 
  19. which blocks SysBeep. 
  20.  
  21. To avoid this, make sure to call SndPlay1(NULL) or SndStop1() to close the channel after
  22. you start a sound going.
  23.  
  24. The easiest way to get a sound to play is to call GetNamedResource(). 
  25.     Handle snd;
  26.     snd=GetNamedResource('snd ',"\pSimple Beep");
  27. However, it's also easy to create your own snd in memory, as a series of commands,
  28. following the instructions in Inside Mac VI.
  29.  
  30. HISTORY:
  31. 3/30/92    dgp wrote it.
  32. 4/1/92    dgp    renamed it and commented out the printf's.
  33. 7/9/93    dgp Test MATLAB in if() instead of #if. 
  34. 5/28/94 dgp Made compatible with Apple's Universal Headers. Thanks to Bob Dougherty 
  35. (wolfgang@cats.ucsc.edu) for reporting the incompatibility.
  36. 9/5/94 dgp removed assumption in printf's that int==short.
  37. 9/10/94 dgp cosmetic
  38. 10/5/94 dgp simplified SndCallBack1 until it stopped crashing when I run native on ppc.
  39. 10/27/94 dgp It is very annoying for the machine to crash anytime you try to quit your
  40. application by escaping via MacsBugs escape to shell. The problem is that CodeWarrior 
  41. 4.5 doesn't attach the atexit() tasks to _EscapeToShell. So I do it here. 
  42. */
  43. #include "VideoToolbox.h"
  44. #include <Sound.h>
  45. static pascal void SndCallBack1(SndChannelPtr channel,SndCommand command);
  46. static SndChannelPtr channel=NULL;
  47. static SndCommand callBack;
  48. #if !defined(NewSndCallBackProc)
  49.     #define NewSndCallBackProc (SndCallBackUPP)
  50.     typedef ProcPtr SndCallBackUPP;
  51. #endif
  52. static void PatchExitToShell(void);
  53.  
  54. OSErr SndPlay1(Handle snd)
  55. {
  56.     int error=0;
  57.     
  58.     static firstTime=1;
  59.     static SndCallBackUPP sndCallBackProc;
  60.  
  61.     if(firstTime){
  62.         sndCallBackProc=NewSndCallBackProc(SndCallBack1);
  63.         if(!MATLAB){
  64.             #if __MWERKS__
  65.                 // In CW _atexit() only gets called if you quit via abort() or exit().
  66.                 PatchExitToShell();
  67.             #else
  68.                 _atexit(SndStop1);
  69.             #endif
  70.         }
  71.         firstTime=0;
  72.     }
  73.     if(channel!=NULL)error=SndDisposeChannel(channel,FALSE);    // wait till done
  74.     channel=NULL;
  75.     if(error)return error;
  76.     if(snd==NULL)return 0;
  77.     error=SndNewChannel(&channel,0,0L,sndCallBackProc);
  78.     if(error){
  79.         printf("%s line %d:SndNewChannel failed with error %d\n",__FILE__,__LINE__,error);
  80.         return error;
  81.     }
  82.     #if UNIVERSAL_HEADERS<2
  83.         error=SndPlay(channel,snd,TRUE);
  84.     #else
  85.         error=SndPlay(channel,(SndListHandle)snd,TRUE);
  86.     #endif
  87.     if(error){
  88.         printf("%s line %d:SndPlay failed with error %d\n",__FILE__,__LINE__,error);
  89.         return error;
  90.     }
  91.     callBack.cmd=callBackCmd;
  92.     callBack.param1=0;
  93.     error=SndDoCommand(channel,&callBack,FALSE);
  94.     if(error)printf("%s line %d:SndDoCommand failed with error %d\n",__FILE__,__LINE__,error);
  95.     return error;
  96. }
  97.  
  98. void SndStop1(void)
  99. {
  100.     if(channel!=NULL)SndDisposeChannel(channel,TRUE);        // immediately
  101.     channel=NULL;
  102. }
  103.  
  104. short SndDone1(void)
  105. // Returns 1 if the last sound initiated by SndPlay1 has finished. Otherwise 0.
  106. {
  107.     return callBack.param1;
  108. }
  109.  
  110. #if (THINK_C || THINK_CPLUS)
  111.     #pragma options(!profile)    // Disable profiling because A5 may be invalid.
  112. #endif
  113.  
  114. static pascal void SndCallBack1(SndChannelPtr channel,SndCommand command)
  115. // Load a short int.
  116. // Called back by sound manager.  Lets us know when sound is done.
  117. {
  118.     channel;    // prevent "unused argument" warning
  119.     command.param1=1;
  120. }
  121.  
  122. /*
  123. The following code, which seems to work on 68k and ppc,
  124. is based on examples that appeared in UseNet csmp-digest-v3-046
  125. by Kevin Bell (kbell@cs.utexas.edu) and Bill Hofmann (wdh@netcom.com)
  126. in response to a query by Steve Coy (stevec@jolt.mpx.com.au)
  127. */
  128.  
  129. #if UNIVERSAL_HEADERS
  130.     #if UNIVERSAL_HEADERS>1
  131.         extern pascal void ExitToShell(void) ONEWORDINLINE(0xA9F4);
  132.     #endif
  133.     typedef UniversalProcPtr TrapAddressType;
  134. #else
  135.     #define UniversalProcPtr ProcPtr
  136.     #define NewRoutineDescriptor(a,b,c) a
  137.     typedef long TrapAddressType;
  138. #endif
  139. static UniversalProcPtr oldExitToShellTrapAddress=NULL;
  140. static void PatchExitToShell(void);
  141. static pascal void MyExitToShell(void);
  142. #include <Traps.h>    // _ExitToShell
  143.  
  144. static void PatchExitToShell(void)
  145. {
  146.     UniversalProcPtr myExitToShellUPP;
  147.     if(oldExitToShellTrapAddress==NULL){
  148.         myExitToShellUPP=NewRoutineDescriptor((ProcPtr)MyExitToShell,kPascalStackBased,GetCurrentISA());
  149.         oldExitToShellTrapAddress=(UniversalProcPtr)GetToolTrapAddress(_ExitToShell);
  150.         SetToolTrapAddress((TrapAddressType)myExitToShellUPP,_ExitToShell);
  151.     }
  152. }
  153.  
  154. static pascal void MyExitToShell(void)
  155. {
  156.     SetCurrentA5();
  157.     SetToolTrapAddress((TrapAddressType)oldExitToShellTrapAddress,_ExitToShell);
  158.     SndStop1();
  159.     ExitToShell();
  160. }
  161.